﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace Utilities
{
    public class TextFileProcessor
    {
        #region Properties

        /// <summary>
        /// Path to the file
        /// </summary>
        public string Path { get; set; }

        public Func<StreamReader, int, char, bool> OnCharacter { get; set; }

        public Func<StreamReader, int, string, bool> OnEndOfLine { get; set; }

        public Action<int> OnEndOfFile { get; set; }

        public int Characters { get; set; }

        public TimeSpan ElapsedTime
        {
            get
            {
                return _stopwatch.Elapsed;
            }
        }

        #endregion

        private Stopwatch _stopwatch = new Stopwatch();

        public void Process()
        {
            _stopwatch.Start();

            Characters = 0;

            try
            {
                using (StreamReader reader = new StreamReader(Path))
                {
                    int n;
                    while ((n = reader.Read()) != -1)
                    {
                        char c = (char)n;

                        // Detect end of line
                        if (c == '\n')
                        {
                            if (OnEndOfLine != null && !OnEndOfLine(reader, Characters, "\n"))
                            {
                                break; // Returning false stops the reading
                            }

                            ++Characters;
                        }
                        else if (c == '\r' && (char)reader.Peek() == '\n')
                        {
                            reader.Read(); // Read the second character                     

                            if (OnEndOfLine != null && !OnEndOfLine(reader, Characters, "\r\n"))
                            {
                                break; // Returning false stops the reading
                            }

                            Characters += 2;
                        }
                        else // Not a new line character
                        {
                            if (OnCharacter != null && !OnCharacter(reader, Characters, c))
                            {
                                break; // Returning false stops the reading
                            }

                            ++Characters;
                        }
                    }

                    // End of file reached
                    if (OnEndOfFile != null)
                    {
                        OnEndOfFile(Characters);
                    }
                }
            }
            finally
            {
                _stopwatch.Stop();
            }            
        }      
    }
}
